package com.smart.village.big.screen.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.smart.village.big.screen.domain.*;
import com.smart.village.big.screen.mapper.*;
import com.smart.village.big.screen.service.PartyOrganizationService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class PartyOrganizationServiceImpl implements PartyOrganizationService {

    @Autowired
    private PartyOrganizationMapper partyOrganizationMapper;
    @Autowired
    private PartyMemberInformationMapper partyMemberInformationMapper;
    @Autowired
    private PartyOrganizationApplicationMapper partyOrganizationApplicationMapper;
    @Autowired
    private BluePlateStudyRoutesMapper bluePlateStudyRoutesMapper;
    @Autowired
    private PersonalInformationMapper personalInformationMapper;
    @Autowired
    private CommentsMapper commentsMapper;

    @Override
    public JSONObject getThreeQuota(String partyOrganizationSerialNumber) {
        JSONObject result = new JSONObject();
        List<String> organizationTypes = Arrays.asList("党委", "总支", "支部");

        // 获取党组织数据
        List<PartyOrganizationCollectStaticVo> collectStaticVos = partyOrganizationMapper.getThreeQuota(partyOrganizationSerialNumber);
        Map<String, List<PartyOrganizationCollectStaticVo>> typeMap = collectStaticVos.stream()
                .collect(Collectors.groupingBy(PartyOrganizationCollectStaticVo::getOrganizationType));

        // 补充缺失的组织类型
        organizationTypes.forEach(type -> {
            if (!typeMap.containsKey(type)) {
                PartyOrganizationCollectStaticVo vo = new PartyOrganizationCollectStaticVo();
                vo.setOrganizationType(type);
                vo.setCnt(0);
                collectStaticVos.add(vo);
            }
        });

        // 获取党组织树结构
        PartyOrganization root = partyOrganizationMapper.selectBySerialNumber(partyOrganizationSerialNumber);
        List<PartyOrganization> treeList = new ArrayList<>();
        if (root != null) {
            treeList.add(root);
        }
        treeList.addAll(partyOrganizationMapper.selectTreeListByParentSerialNumber(partyOrganizationSerialNumber, ""));

        // 处理党组织成员名单
        treeList.forEach(org -> {
            String memberNames = partyOrganizationApplicationMapper.getPartyOrganizationMemberNamesCurrent(org.getPartyOrganizationSerialNumber());
            if (StringUtils.isEmpty(memberNames)) {
                memberNames = "暂无党员";
            }
            org.setPartyMemberNameList(memberNames);
        });

        // 构建结果
        organizationTypes.forEach(type -> {
            List<PartyOrganizationCollectStaticVo> vos = typeMap.getOrDefault(type, Collections.emptyList());
            String typeKey = type.toLowerCase();
            switch (typeKey) {
                case "党委":
                    typeKey = "committee";
                    break;
                case "总支":
                    typeKey = "generalBranch";
                    break;
                case "支部":
                    typeKey = "branch";
                    break;
                default:
            }
            result.put(typeKey, vos.stream().map(PartyOrganizationCollectStaticVo::getCnt).reduce(0, Integer::sum));
            result.put(typeKey + "List", treeList.stream()
                    .filter(org -> type.equals(org.getPartyOrganizationType()))
                    .collect(Collectors.toList()));
        });

        return result;
    }

    @Override
    public List<StudyRoutesVo> studyRoutes(String studyRouteSerialNumber) {

        List<StudyRoutesVo> result = new ArrayList<>();
        if (StringUtils.isEmpty(studyRouteSerialNumber)) {
            for (BluePlateStudyRoutes bluePlateStudyRoute : bluePlateStudyRoutesMapper.getBluePlateStudyRoutes("")) {
                List<BluePlateInformation> bluePlateInformationListByStudyRouteSerialNumber = bluePlateStudyRoutesMapper
                        .getBluePlateInformationListByStudyRouteSerialNumber
                                (bluePlateStudyRoute.getBluePlateStudyRouteSerialNumber());
                StudyRoutesVo studyRoutesVo = new StudyRoutesVo();
                studyRoutesVo.setName(bluePlateStudyRoute.getBluePlateStudyRoute());
                studyRoutesVo.setType("FeatureCollection");
                studyRoutesVo.setNumber(bluePlateStudyRoute.getBluePlateStudyRouteSerialNumber());
                List<FeaturesVo> featuresVos = Lists.newArrayList();
                for (BluePlateInformation bluePlateInformation : bluePlateInformationListByStudyRouteSerialNumber) {
                    FeaturesVo featureVo = new FeaturesVo();
                    featureVo.setType("Feature");
                    PropertiesVo propertiesVo = new PropertiesVo();
                    propertiesVo.setNumber(bluePlateInformation.getBluePlateSerialNumber());
                    propertiesVo.setAddress(bluePlateInformation.getAddress());
                    propertiesVo.setBluePlateName(bluePlateInformation.getBluePlateName());
                    propertiesVo.setIntroduce(bluePlateInformation.getIntroduce());
                    propertiesVo.setImages(bluePlateInformation.getImages());
                    featureVo.setProperties(propertiesVo);
                    GeometryVo geometryVo = new GeometryVo();
                    geometryVo.setType("Point");
                    String coord = bluePlateInformation.getCoord();
                    if (ObjectUtils.isEmpty(coord)) {
                        continue;
                    }
                    JSONArray objects = JSONArray.parseArray(coord);
                    geometryVo.setCoordinates(objects.toJavaList(Object.class));
                    featureVo.setGeometry(geometryVo);
                    featuresVos.add(featureVo);
                }
                studyRoutesVo.setFeatures(featuresVos);
                result.add(studyRoutesVo);
            }

        } else {
            for (BluePlateStudyRoutes bluePlateStudyRoute : bluePlateStudyRoutesMapper.getBluePlateStudyRoutes(studyRouteSerialNumber)) {
                List<BluePlateInformation> bluePlateInformationListByStudyRouteSerialNumber = bluePlateStudyRoutesMapper
                        .getBluePlateInformationListByStudyRouteSerialNumber
                                (bluePlateStudyRoute.getBluePlateStudyRouteSerialNumber());
                StudyRoutesVo studyRoutesVo = new StudyRoutesVo();
                studyRoutesVo.setName(bluePlateStudyRoute.getBluePlateStudyRoute());
                studyRoutesVo.setType("FeatureCollection");
                studyRoutesVo.setNumber(bluePlateStudyRoute.getBluePlateStudyRouteSerialNumber());
                List<FeaturesVo> featuresVos = Lists.newArrayList();
                for (BluePlateInformation bluePlateInformation : bluePlateInformationListByStudyRouteSerialNumber) {
                    FeaturesVo featureVo = new FeaturesVo();
                    featureVo.setType("Feature");
                    PropertiesVo propertiesVo = new PropertiesVo();
                    propertiesVo.setNumber(bluePlateInformation.getBluePlateSerialNumber());
                    propertiesVo.setAddress(bluePlateInformation.getAddress());
                    propertiesVo.setIntroduce(bluePlateInformation.getIntroduce());
                    propertiesVo.setBluePlateName(bluePlateInformation.getBluePlateName());
                    propertiesVo.setImages(bluePlateInformation.getImages());
                    featureVo.setProperties(propertiesVo);
                    GeometryVo geometryVo = new GeometryVo();
                    geometryVo.setType("Point");
                    String coord = bluePlateInformation.getCoord();
                    if (ObjectUtils.isEmpty(coord)) {
                        continue;
                    }
                    JSONArray objects = JSONArray.parseArray(coord);
                    geometryVo.setCoordinates(objects.toJavaList(Object.class));
                    featureVo.setGeometry(geometryVo);
                    featuresVos.add(featureVo);
                }
                studyRoutesVo.setFeatures(featuresVos);
                result.add(studyRoutesVo);

            }
        }
        return result;
    }

    @Override
    public List<BluePlateStudyRoutes> getAllBluePlateStudyRoutes() {
        return bluePlateStudyRoutesMapper.getAllBluePlateStudyRoutes();
    }

    @Override
    public List<StudyRoutesVo> demonstrationSite(String tagSerialNumber, String villageSerialNumber) {
        List<StudyRoutesVo> result = new ArrayList<>();
        if (StringUtils.isEmpty(tagSerialNumber)) {
            for (BluePlateTags bluePlateTags : bluePlateStudyRoutesMapper.getAllBluePlateTags("")) {
                List<BluePlateInformation> bluePlateInformationListByStudyRouteSerialNumber = bluePlateStudyRoutesMapper
                        .getBluePlateInformationListByTagSerialNumberAndVillage
                                (bluePlateTags.getBluePlateTagSerialNumber(), villageSerialNumber);
                StudyRoutesVo studyRoutesVo = new StudyRoutesVo();
                studyRoutesVo.setName(bluePlateTags.getBluePlateTag());
                studyRoutesVo.setType("FeatureCollection");
                studyRoutesVo.setNumber(bluePlateTags.getBluePlateTagSerialNumber());
                List<FeaturesVo> featuresVos = Lists.newArrayList();
                for (BluePlateInformation bluePlateInformation : bluePlateInformationListByStudyRouteSerialNumber) {
                    FeaturesVo featureVo = new FeaturesVo();
                    featureVo.setType("Feature");
                    PropertiesVo propertiesVo = new PropertiesVo();
                    propertiesVo.setNumber(bluePlateInformation.getBluePlateSerialNumber());
                    propertiesVo.setAddress(bluePlateInformation.getAddress());
                    propertiesVo.setIntroduce(bluePlateInformation.getIntroduce());
                    propertiesVo.setImages(bluePlateInformation.getImages());
                    propertiesVo.setBluePlateName(bluePlateInformation.getBluePlateName());
                    propertiesVo.setContactPhone(bluePlateInformation.getContactPhone());
                    featureVo.setProperties(propertiesVo);
                    GeometryVo geometryVo = new GeometryVo();
                    geometryVo.setType("Point");
                    String coord = bluePlateInformation.getCoord();
                    if (ObjectUtils.isEmpty(coord)) {
                        continue;
                    }
                    JSONArray objects = JSONArray.parseArray(coord);
                    geometryVo.setCoordinates(objects.toJavaList(Object.class));
                    featureVo.setGeometry(geometryVo);
                    featuresVos.add(featureVo);
                }
                studyRoutesVo.setFeatures(featuresVos);
                result.add(studyRoutesVo);
            }

        } else {
            for (BluePlateTags bluePlateTags : bluePlateStudyRoutesMapper.getAllBluePlateTags(tagSerialNumber)) {
                List<BluePlateInformation> bluePlateInformationListByStudyRouteSerialNumber = bluePlateStudyRoutesMapper
                        .getBluePlateInformationListByTagSerialNumberAndVillage
                                (bluePlateTags.getBluePlateTagSerialNumber(), villageSerialNumber);
                StudyRoutesVo studyRoutesVo = new StudyRoutesVo();
                studyRoutesVo.setName(bluePlateTags.getBluePlateTag());
                studyRoutesVo.setType("FeatureCollection");
                studyRoutesVo.setNumber(bluePlateTags.getBluePlateTagSerialNumber());
                List<FeaturesVo> featuresVos = Lists.newArrayList();
                for (BluePlateInformation bluePlateInformation : bluePlateInformationListByStudyRouteSerialNumber) {
                    FeaturesVo featureVo = new FeaturesVo();
                    featureVo.setType("Feature");
                    PropertiesVo propertiesVo = new PropertiesVo();
                    propertiesVo.setNumber(bluePlateInformation.getBluePlateSerialNumber());
                    propertiesVo.setAddress(bluePlateInformation.getAddress());
                    propertiesVo.setIntroduce(bluePlateInformation.getIntroduce());
                    propertiesVo.setImages(bluePlateInformation.getImages());
                    propertiesVo.setBluePlateName(bluePlateInformation.getBluePlateName());
                    propertiesVo.setContactPhone(bluePlateInformation.getContactPhone());
                    featureVo.setProperties(propertiesVo);
                    GeometryVo geometryVo = new GeometryVo();
                    geometryVo.setType("Point");
                    String coord = bluePlateInformation.getCoord();
                    if (ObjectUtils.isEmpty(coord)) {
                        continue;
                    }
                    JSONArray objects = JSONArray.parseArray(coord);
                    geometryVo.setCoordinates(objects.toJavaList(Object.class));
                    featureVo.setGeometry(geometryVo);
                    featuresVos.add(featureVo);
                }
                studyRoutesVo.setFeatures(featuresVos);
                result.add(studyRoutesVo);

            }
        }
        return result;
    }

    @Override
    public JSONObject getMicroPartyOrganizationManager(String partyOrganizationSerialNumber) {
        JSONObject result = new JSONObject();
        JSONObject information = partyOrganizationMapper.getMicroPartyOrganizationInformation(partyOrganizationSerialNumber);
        List<JSONObject> positionList = partyOrganizationMapper.getMicroPositionInformation(partyOrganizationSerialNumber);
        List<JSONObject> briefInformation = partyOrganizationMapper.getMicroBriefInformation(partyOrganizationSerialNumber);
        briefInformation.forEach(jsonObject -> {
            String organizationType = jsonObject.getString("organizationType");
            String type = "";
            switch (organizationType) {
                case "党委":
                    type = "committee";
                    break;
                case "总支":
                    type = "generalBranch";
                    break;
                case "支部":
                    type = "branch";
                    break;
                case "党员人数":
                    type = "partyMember";
                    break;
                default:
                    break;
            }
            jsonObject.put("organizationType", type);
        });
        result.put("information", information);
        result.put("positionList", positionList);
        result.put("briefList", briefInformation);
        return result;
    }

    @Override
    public PartyOrganizationTreeNode getMicroPartyOrganizationTree(String partyOrganizationSerialNumber) {
        String maxTenureSerialNumber = partyOrganizationMapper.getMaxTenureSerialNumber(partyOrganizationSerialNumber);
        if (maxTenureSerialNumber == null) {
            return new PartyOrganizationTreeNode("", "", "", "", "");
        }
        List<JSONObject> partyOrganizationPositionData = partyOrganizationMapper.getPartyOrganizationPositionTree(maxTenureSerialNumber, partyOrganizationSerialNumber);
        return buildTree(partyOrganizationPositionData);
    }

    @Override
    public JSONObject getMicroPartyMemberInformation(String iDCardNumber) {
        return partyMemberInformationMapper.getMicroPartyMemberInformation(iDCardNumber);
    }

    @Override
    public JSONObject getMicroAccountInformation(String openId) {
        return partyMemberInformationMapper.getMicroAccountInformation(openId);
    }

    @Override
    public int getMicroIfRealCheck(String name, String iDCardNumber) {
        // 如果没在人口表中 则不让继续操作
        int microIfRealCheck = personalInformationMapper.getMicroIfRealCheck(name, iDCardNumber);
        if (microIfRealCheck > 0) {
            // 如果 user 和 身份证号绑定了 则不让继续操作
            int microIfBindingUser = personalInformationMapper.getMicroIfBindingUser(iDCardNumber);
            if (microIfBindingUser > 0) {
                return 0;
            } else {
                // 可以继续操作
                return 1;
            }
        } else {
            return 0;
        }
    }

    @Override
    public List<BluePlateInformation> getMicroBluePlateInformationListByTagSerialNumber(String tagSerialNumber, String search) {
        return bluePlateStudyRoutesMapper.getMicroBluePlateInformationListByTagSerialNumber(tagSerialNumber, search);
    }

    @Override
    public JSONObject getMicroManagerPartyMemberList(String partyOrganizationSerialNumber, String search, int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<HashMap<String, Object>> microManagerPartyMemberList = partyMemberInformationMapper.getMicroManagerPartyMemberList(partyOrganizationSerialNumber, search);
        PageInfo<HashMap<String, Object>> pageInfo = new PageInfo<>(microManagerPartyMemberList);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("list", pageInfo.getList());
        jsonObject.put("total", pageInfo.getTotal());
        return jsonObject;
    }

    @Override
    public JSONObject getMicroManagerPartyMemberDevelop(String partyOrganizationSerialNumber, String search, int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<HashMap<String, Object>> microManagerPartyMemberList = partyMemberInformationMapper.getMicroManagerPartyMemberDevelop(partyOrganizationSerialNumber, search);
        PageInfo<HashMap<String, Object>> pageInfo = new PageInfo<>(microManagerPartyMemberList);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("list", pageInfo.getList());
        jsonObject.put("total", pageInfo.getTotal());
        return jsonObject;
    }

    @Override
    public JSONObject getMicroManagerPartyOrganizationTenure(String partyOrganizationSerialNumber) {
        JSONObject result = new JSONObject();
        JSONObject information = partyOrganizationMapper.getMicroPartyOrganizationInformation(partyOrganizationSerialNumber);
        List<JSONObject> personalList = partyOrganizationMapper.getMicroPositionInformationNew(partyOrganizationSerialNumber);
        List<JSONObject> briefInformation = partyOrganizationMapper.getMicroBriefInformation(partyOrganizationSerialNumber);
        briefInformation.forEach(jsonObject -> {
            String organizationType = jsonObject.getString("organizationType");
            String type = "";
            switch (organizationType) {
                case "党委":
                    type = "committee";
                    break;
                case "总支":
                    type = "generalBranch";
                    break;
                case "支部":
                    type = "branch";
                    break;
                case "党员人数":
                    type = "partyMember";
                    break;
                default:
                    break;
            }
            jsonObject.put("organizationType", type);
        });
        result.put("information", information);
        result.put("personalList", personalList);
        result.put("briefList", briefInformation);

        String maxTenureSerialNumber = partyOrganizationMapper.getMaxTenureSerialNumber(partyOrganizationSerialNumber);
        if (StringUtils.isEmpty(maxTenureSerialNumber)) {
            result.put("treeNode", new PartyOrganizationTreeNode("", "", "", "", ""));
            return result;
        }
        List<JSONObject> partyOrganizationPositionData = partyOrganizationMapper.getPartyOrganizationPositionTree(maxTenureSerialNumber, partyOrganizationSerialNumber);
        result.put("treeNode", buildTree(partyOrganizationPositionData));
        return result;
    }

    @Override
    public JSONObject getPartyMemberComments(String partyOrganizationSerialNumber, String replyStatus, int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<Comments> commentsList = commentsMapper.getPartyMemberComments(partyOrganizationSerialNumber, replyStatus);
        PageInfo<Comments> pageInfo = new PageInfo<>(commentsList);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("list", pageInfo.getList());
        jsonObject.put("total", pageInfo.getTotal());
        return jsonObject;
    }

    @Override
    public JSONObject getPartyMemberComplaints(String partyOrganizationSerialNumber, String replyStatus, int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<JSONObject> commentsList = commentsMapper.getPartyMemberComplaints(partyOrganizationSerialNumber, replyStatus);
        PageInfo<JSONObject> pageInfo = new PageInfo<>(commentsList);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("list", pageInfo.getList());
        jsonObject.put("total", pageInfo.getTotal());
        return jsonObject;
    }

    @Override
    public JSONObject getPartyMemberCommentsDetail(String complaintId) {
        return commentsMapper.getPartyMemberCommentsDetail(complaintId);
    }

    @Override
    public JSONObject getMicroPartyMemberEvent(String partyMemberSerialNumber, String type, int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<JSONObject> eventList = partyMemberInformationMapper.getMicroPartyMemberEvent(partyMemberSerialNumber, type);
        for (JSONObject event : eventList) {
            List<JSONObject> attachmentList = partyMemberInformationMapper.getMicroPartyMemberEventAttachment(event.getString("Event_SerialNumber"));
            event.put("attachmentList", attachmentList);
        }
        PageInfo<JSONObject> pageInfo = new PageInfo<>(eventList);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("list", pageInfo.getList());
        jsonObject.put("total", pageInfo.getTotal());
        return jsonObject;
    }

    @Override
    public List<JSONObject> getMicroPartyMemberAttachmentTypeList(String partyMemberSerialNumber) {
        return partyMemberInformationMapper.getMicroPartyMemberAttachmentTypeList(partyMemberSerialNumber);
    }

    @Override
    public List<JSONObject> getMicroPartyMemberAttachmentList(String partyMemberSerialNumber, String type) {
        return partyMemberInformationMapper.getMicroPartyMemberAttachmentList(partyMemberSerialNumber, type);
    }

    @Override
    public JSONObject getFriendShipLinks(int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<JSONObject> list = partyOrganizationMapper.getFriendShipLinks();
        PageInfo<JSONObject> pageInfo = new PageInfo<>(list);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("list", pageInfo.getList());
        jsonObject.put("total", pageInfo.getTotal());
        return jsonObject;
    }

    public static PartyOrganizationTreeNode buildTree(List<JSONObject> data) {
        Map<String, PartyOrganizationTreeNode> nodeMap = new HashMap<>();
        PartyOrganizationTreeNode root = null;

        // Step 1: Create all nodes and store them in a map
        for (JSONObject row : data) {
            String serialNumber = ObjectUtils.isEmpty(row.get("Tenure_Position_SerialNumber")) ? "" : row.getString("Tenure_Position_SerialNumber");
            String parentSerialNumber = ObjectUtils.isEmpty(row.get("Parent_SerialNumber")) ? "" : row.getString("Parent_SerialNumber");
            String position = ObjectUtils.isEmpty(row.get("Party_Position")) ? "" : row.getString("Party_Position");
            String personalName = ObjectUtils.isEmpty(row.get("Personal_Name")) ? "" : row.getString("Personal_Name");
            String pictureURL = ObjectUtils.isEmpty(row.get("pictureURL")) ? "" : row.getString("pictureURL");

            PartyOrganizationTreeNode node = new PartyOrganizationTreeNode(serialNumber, parentSerialNumber, position, personalName, pictureURL);
            nodeMap.put(serialNumber, node);

            // Identify the root node (no parent)
            if (parentSerialNumber == null || parentSerialNumber.isEmpty()) {
                root = node;
            }
        }

        // Step 2: Build the tree structure by linking parent and children
        for (JSONObject row : data) {
            String serialNumber = ObjectUtils.isEmpty(row.get("Tenure_Position_SerialNumber")) ? "" : row.getString("Tenure_Position_SerialNumber");
            String parentSerialNumber = ObjectUtils.isEmpty(row.get("Parent_SerialNumber")) ? "" : row.getString("Parent_SerialNumber");

            if (parentSerialNumber != null && !parentSerialNumber.isEmpty()) {
                PartyOrganizationTreeNode childNode = nodeMap.get(serialNumber);
                PartyOrganizationTreeNode parentNode = nodeMap.get(parentSerialNumber);
                if (parentNode != null) {
                    if (childNode != null) {
                        parentNode.addChild(childNode);
                    }
                }
            }
        }

        return root;
    }

}
